package edu.rit.checkers;

import edu.rit.pj.Comm;

/**
 * Use this class to run a sequential test on the Checkers problem
 * 
 * @author Ian Tewksbury (ict8574@rit.edu)
 */
public class CheckersSeq {
	/**
	 * The usage message for running this program
	 */
	private static final String USAGE =
		"usage: CheckersSeq " +
		"<startDepth> <increaseDepth> <maxTime> <maxTimePerDepth>\n" +
		"<startDepth> the start depth of the tree\n" +
		"<increaseDepth> the amount to increase the depth " +
			"of the tree by if time allows\n" +
		"<maxTime> the max time to run the search\n" +
		"<maxTimePerDepth> the max time to spend searching " +
			"each depth increase\n";

	/**
	 * Run one Checkers sequential test based on given args
	 * 
	 * @param args
	 * 	args[0] <startDepth> the start depth of the tree
	 * 	args[1] <increaseDepth> the amount to increase the depth of the tree
	 *by if time allows
	 * 	args[2] <maxTime> the max time to run the search
	 * 	args[3] <maxTimePerDepth> the max time to spend searching
	 * 
	 * @throws Exception parallel stuff can throw Exceptions
	 */
	public static void main(String[] args) throws Exception {
		//PJ init
		Comm.init(args);
		
		int[] parsedArgs = Helpers.parseArgs(args);
		
		if(parsedArgs != null) {
			CheckersSeq.runSeqTest(parsedArgs[0], parsedArgs[1], parsedArgs[2],
				parsedArgs[3], true);
		} else {
			System.out.println(USAGE);
		}
	}
	
	/**
	 * Run a sequential test based on the given parameters.  Grows a tree for
	 * the max amount of time and then does a final a-b on it.  Will print
	 * out info about the tree before and after the final a-b if requested
	 * 
	 * @param startDepth the start max depth of the tree
	 * @param depthIncrease the amount to increase the max depth by
	 * if time allows
	 * @param timeLimit the max time to search the tree for
	 * @param timeLimitForDepth the max time to search a specific max depth
	 * @param printInfo whether to print info about the tree

	 * @return the number of nodes explored while building the tree
	 * 
	 * @throws Exception parallel stuff can throw Exceptions 
	 */
	public static long runSeqTest(int startDepth, int depthIncrease,
			int timeLimit, int timeLimitForDepth, boolean printInfo)
		throws Exception {
		
		ConfigNode.resetNodeId();
		
		long tStart, tABStart;
		
		//get start time
		tStart = System.currentTimeMillis();
		
		//create logger
		Logger log = new Logger(System.out);
		log.loggerOn(printInfo);
		
		//build the tree
		log.println("SEARCH TREE");
		ConfigTree tree = null;
		tree = CheckersSeq.buildTree(startDepth, depthIncrease, timeLimit,
			timeLimitForDepth);
		
		//print tree info and search time
		log.println(tree);
		log.println("Search Time: " +
			(System.currentTimeMillis() - tStart));
		
		//do a final alpha beta and print its running time
		log.println("\nFINAL ALPHA-BETA");
		tABStart = System.currentTimeMillis();
		tree.alphaBeta();
		log.println(tree);
		log.println("Final Alpha-Beta Time: " +
			(System.currentTimeMillis() - tABStart));
		
		//return total running time
		log.println("Total Time: " +
			(System.currentTimeMillis() - tStart));
		
		return tree.getAddedNodes();
	}
	
	/**
	 * This actually does the tree building using a sequential algorithm.
	 * Then tree is grown until the max time has been reached.  If a depth
	 * time limit is reached then the tree size is increased and the tree is
	 * continually searched.
	 * 
	 * @param startMaxDepth the starting max depth of the tree to grow
	 * @param depthIncreaseAmount the amount to increase the max depth by if
	 * there is time
	 * @param totalTimeLimit the max time to grow the tree for
	 * @param depthTimeLimit the max time to search a specific max depth of
	 * the tree
	 * 
	 * @return the tree that has been built based on the given parameters
	 */
	private static ConfigTree buildTree(
		int startMaxDepth, int depthIncreaseAmount, int totalTimeLimit,
		int depthTimeLimit) {
		
		ConfigNode root = new ConfigNode();
		ConfigTree tree = new ConfigTree(startMaxDepth, root);
		
		long stopTime = System.currentTimeMillis() + totalTimeLimit;
		while(System.currentTimeMillis() < stopTime) {
			//grow tree till either depth time reached or stop time
			//	reached
			tree.growTreeToCurrDepthLimit(
				Math.min(
					(System.currentTimeMillis() + depthTimeLimit),
					stopTime));
			
			//increase possible tree size
			tree.increaseMaxDepth(depthIncreaseAmount);
		}
		
		return tree;
	}
}
